<Html>
    <head>
        <title>C#动态脚本中方法返回自定义类型</title>
    </head>
    <body>
        <script>
            /*
                在动态编译的场景中，返回自定义类型（如ExamDto） 确实存在类型匹配问题。

                我们来详细解释下这个问题的本质和解决方案：


                   1、问题的本质

                            ①、类型隔离：  动态编译生成的程序集在运行时是一个"独立的类型系统"，即使源代码完全相同，动态生成的EaxmDto与你项目中的ExamDto也是两个不同的类型。

                            ②、CLR 类型识别：  CLR 根据"程序集"和"类型全名"来识别类型，动态生成的类型虽然结构相同，但是程序集不同，因此不能直接转换。
            */  

            /*
                  2、直接转换造成的异常

                            以下代码会抛出 InvalidCastException (非法转换异常)；

                                 // 错误示例： 无法直接转换为项目中的 ExamDto类型

                                 var result = awai _compilerService.CompilerAndExecuteAsync(code);
                                 var examDto =(ExamDto)result;
            */

            /*
                  3、解决方案

                            ★、方案1：使用接口或基类 (推荐)

                                        定义一个公共接口，让动态代码实现该接口：

                                        // 定义公共接口
                                        public interface IExamResult
                                        {
                                            string Name{get;set;}

                                            int Score{get;set;}
                                        }

                                        // 修改动态代码实现该接口
                                        public class DynamicCode:IExamResult
                                        {
                                            public string Name {get;set;} ="Test";
                                            public int Score {get;set;} =90;

                                            // 声明委托类型的属性（可选）
                                            public Func<int, int, int> Operation { get; set; } = (a, b) => a + b;

                                            public IExamResult Excute()
                                            {
                                                return this;
                                            }
                                        }

                                        // 通过接口访问(安全转换)
                                        var result = await _compilerService.CompilerAndExecuteAsync(code);
                                        if(result is IExamResult examDto)
                                        {
                                            
                                        }

                            ★、方案二：反射访问属性

                                        不依赖接口，直接通过反射获取属性值：

                                        var result = await _compilerService.CompileAndExecuteAsync(code);
                                        Type resultType = result.GetType();

                                        string name = (string)resultType.GetProperty("Name")?.GetValue(result);
                                        int score = (int)resultType.GetProperty("Score")?.GetValue(result);


                            ★、方案三：使用 JSON 序列化（灵活方案）

                                        将对象序列化为JSON，再反序列化为项目中的类型：

                                        // 修改动态代码，返回json字符串
                                        public class DynamicCode
                                        {
                                            public string Execute()
                                            {
                                                var dto = new {Name="Test",Score=90};
                                                return System.Text.Json.JsonSerializer.Serialize(dto);
                                            }
                                        }


                            最佳实践建议:

                                    优先使用接口：定义清晰的契约，保持类型安全。

                                    避免复杂类型：动态代码返回简单数据结构（如 DTO）或基本类型。

                                    考虑序列化：对于复杂场景，JSON 序列化是最灵活的方案。
            */
        </script>
    </body>
</Html>